﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Reflection;
using System.ComponentModel;
using devtm.Editor.TypeSelector;
using System.Configuration;
using Microsoft.VisualStudio.Modeling;

using DslModeling = global::Microsoft.VisualStudio.Modeling;
using DslDesign = global::Microsoft.VisualStudio.Modeling.Design;
using DslDiagrams = global::Microsoft.VisualStudio.Modeling.Diagrams;
using System.Diagnostics;


namespace devtm.AutoMapper
{

	public static class ContainerTypes
	{


		static SourceTypes SourceTypes;
		static ContainerTypes()
		{
			//_noneType = CreateInternal("", " (none)", "", TypeEnum.TypeReturn);
			SourceTypes = new SourceTypes();
			Initialize();
		}


		//private static Type CreateInternal(string Namespace, string Name, string assembly, TypeEnum type)
		//{
		//    var oo = new AbstrType(Namespace, Name, assembly);
		//    return oo;
		//}

        public static IEnumerable<Type> GetTypes(DslModeling.Store store, HashSet<String> namespaces, Func<Type, bool> filter)
		{

			Initialize();

            foreach (Type item in SourceTypes.GetTypes(store, namespaces, filter))
				yield return item;

		}


        public static IEnumerable<Type> GetTypes(DslModeling.Store store, HashSet<String> namespaces, TypeEnum context)
		{

			Initialize();

            Func<Type, bool> filter = null;

			switch (context)
			{
				case TypeEnum.Enum:
					filter = IsEnum;
					break;

				//case TypeEnum.Validator:
				//    filter = IsValidator;
				//    break;

				//case TypeEnum.TypeConverter:
				//    filter = IsTypeConverter;
				//    break;

				case TypeEnum.TypeReturn:
					filter = IsTypeReturn;
					break;

				default:
					filter = null;
					break;

			}


			if (filter == null)
                foreach (Type item in SourceTypes.GetTypes(store, namespaces))
					yield return item;

			else
                foreach (Type item in SourceTypes.GetTypes(store, namespaces, filter))
					yield return item;


		}

		private static void Initialize()
		{

			if (SourceTypes.Source.Count() != 0)
				return;

			ITypeProvider i = null;
			i = new ReferenceTypeProvider(null);		
			i = new PrimitiveTypeProvider();
			i = new SolutionTypeProvider();
            //i = new DynamicTypeProvider();

		}



        public static IEnumerable<Type> GetTypes(DslModeling.Store store, HashSet<String> namespaces)
		{

			Initialize();

			foreach (var item in SourceTypes.GetTypes(store, namespaces))
				yield return item;

		}

        private static Type _noneType = null;
        public static Type GetNoneType()
		{
			return _noneType;
		}

		//public static bool IsValidator(Type type) { return type.IsSubclassOf(typeof(ConfigurationValidatorBase)); }
		//public static bool IsTypeConverter(Type type) { return type.IsSubclassOf(typeof(ConfigurationConverterBase)); }
        public static bool IsEnum(Type type) { return type.IsEnum; }
        public static bool IsTypeReturn(Type type) { return type.IsPrimitive || type == typeof(string); }
        public static bool IsAvaibleTypeReturn(Type type) { return type.IsPrimitive || type == typeof(string) || type.IsEnum; }


        public static IEnumerable<Type> GetFromReference(DslModeling.Store store, HashSet<String> namespaces, Func<Type, bool> filter)
		{
			return SourceTypes.GetItem<ReferenceTypeProvider>().GetTypes(store, namespaces, filter);
		}

        public static IEnumerable<Type> GetFromReference(DslModeling.Store store, HashSet<String> namespaces)
		{
			return SourceTypes.GetItem<ReferenceTypeProvider>().GetTypes(store, namespaces);
		}

        public static IEnumerable<Type> GetFromSolution<T>(DslModeling.Store store, HashSet<String> namespaces)
        {

            foreach (var item in TypeHelper.GetAvailableTypes<T>(store))
            {
                if (item != null)
                {

                    string nn = string.Empty;

                    try
                    {

                        if (item.IsNested)
                            nn = item.FullName.Substring(0, item.FullName.Length - item.Name.Length - 1);

                        else
                        {
                            nn = item.Namespace;

                        }
                        

                    }
                    catch (Exception e)
                    {

                        StackTrace st = new StackTrace(e, true);

                        var fr = st.GetFrame(0);

                        throw;
                    }

                    if (namespaces == null || (namespaces.Contains(nn)))
                        yield return item;
                    
                }
            };
        }

        public static IEnumerable<Type> GetFromPrimitive()
		{
			return SourceTypes.GetItem<PrimitiveTypeProvider>().GetTypes(null, null);
		}



        private static List<Type> _list = new List<Type>();
        public static void PutInCache(IList<Type> list)
        {
            _list.Clear();
            _list.AddRange(list);
        }

        public static void ClearCache()
        {
            _list.Clear();
        }

        public static List<Type> Types { get { return _list; } }

	}

}







//[ThreadStatic]
//public static new Dictionary<TypeEnum, Dictionary<string, Type>> Types;

//[ThreadStatic]
//public static new Dictionary<string, Assembly> Assemblies;

//[ThreadStatic]
//private static ITypeProvider _customs;

//private static TypeContainer _typeContainer;
//public static TypeContainer TypeContainer
//{
//    get { return _typeContainer; }
//    set
//    {
//        _typeContainer = value;
//    }
//}

//private static void Add()
//{

//    // on s'assure que le projet reference System.Configuration
//    StoreHostingProject.EnsureProjectReferencesAssembly(ConfigurationModel.GetStore(),
//        typeof(System.Configuration.ConfigurationElement).Assembly);

//    // trouve les assemblies referencées par l'appli.
//    var i = StoreHostingProject.ProjectReferencesAssemblies(ConfigurationModel.GetStore()).ToList();

//    //On rentre les types
//    foreach (Assembly item in i)
//        if (!Assemblies.ContainsKey(item.FullName))
//            AddAssembly(item);

//}

//private static void AddPrimitives()
//{
//    //AddExternalType(typeof(bool), TypeEnum.TypeReturn);
//    //AddExternalType(typeof(Byte), TypeEnum.TypeReturn);
//    //AddExternalType(typeof(char), TypeEnum.TypeReturn);
//    //AddExternalType(typeof(DateTime), TypeEnum.TypeReturn);
//    //AddExternalType(typeof(Double), TypeEnum.TypeReturn);
//    //AddExternalType(typeof(Guid), TypeEnum.TypeReturn);
//    //AddExternalType(typeof(Int16), TypeEnum.TypeReturn);
//    //AddExternalType(typeof(Int32), TypeEnum.TypeReturn);
//    //AddExternalType(typeof(Int64), TypeEnum.TypeReturn);
//    //AddExternalType(typeof(SByte), TypeEnum.TypeReturn);
//    //AddExternalType(typeof(Single), TypeEnum.TypeReturn);
//    //AddExternalType(typeof(String), TypeEnum.TypeReturn);
//    //AddExternalType(typeof(Type), TypeEnum.TypeReturn);
//    //AddExternalType(typeof(UInt16), TypeEnum.TypeReturn);
//    //AddExternalType(typeof(UInt32), TypeEnum.TypeReturn);
//    //AddExternalType(typeof(UInt64), TypeEnum.TypeReturn);
//    //AddExternalType(typeof(TimeSpan), TypeEnum.TypeReturn);

//    //AddInternalType("", "ConnectionStringName", "", TypeEnum.TypeReturn);
//    //AddInternalType("", "HostAddress", "", TypeEnum.TypeReturn);

//}

//private static void AddAssembly(Assembly ass)
//{

//    Assemblies.Add(ass.FullName, ass);

//    Type ConfigurationValidatorAttribute = typeof(System.Configuration.ConfigurationValidatorAttribute);
//    Type ConfigurationConverterBase = typeof(TypeConverter);

//    foreach (Type item in ass.GetTypes())
//    {

//        if (item.IsSubclassOf(ConfigurationValidatorAttribute))
//            AddExternalType(item, TypeEnum.Validator);

//        else if (item.IsSubclassOf(ConfigurationConverterBase))
//            AddExternalType(item, TypeEnum.TypeConverter);

//        else if (item.IsEnum)
//            AddExternalType(item, TypeEnum.Enum);

//    }
//}

//private static void AddExternalType(Type item, TypeEnum type)
//{
//    if (Types[type].ContainsKey(item.AssemblyQualifiedName))
//        return;

//    Types[type].Add(item.AssemblyQualifiedName, item);

//}

//private static void AddInternalType(string Namespace, string name, string assembly, TypeEnum type)
//{

//    var oo = CreateInternal(Namespace, name, assembly, type);

//    if (Types[type].ContainsKey(oo.AssemblyQualifiedName))
//        return;

//    Types[type].Add(oo.AssemblyQualifiedName, oo);
//}